/**
 * This is a base framework to create Classes for OOP.
 * All attributes and functions can be accessed outer. 
 * because all attributes will be appended to "this", all functions will be appended to "Class.prototype".
 * You should seperate them with "_" as the prefix of member names.
 * e.g.
 *   _member is private member,
 *   member is public member.
 */

(function(ns) {
	ns = ns || window;
	ns.Class = {};
	
	function emptyFunction() {}
	
	/*
	 * param:
	 * {
	 * 	 Namesapce : "a.b.c.d.ClassB",
	 *   Extends : a.b.c.ClassA,
	 *   Constructor : function() {},
	 *   Fields : 
	 *   {
	 *     field1 : 34,
	 *     field2 : null
	 *   },
	 *   Methods : 
	 *   {
	 *     method1 : function() {},
	 *     method2 : function() {}
	 *   },
	 *   Statics :
	 *   {
	 *     MEMBER : 23,
	 *     METHOD : function() {}
	 *   }
	 * }
	 */
	ns.Class.create = function(param) {
		if (!param) {
			return emptyFunction;
		}
		
		var clazz = function(){
			//analyse fields of the class
			if (param.Fields) {
				var fields = param.Fields;
				for (var field in fields) {
					if (typeof fields[field] == "function") {
						throw new TypeError("Field [" + field + "] cannot be a function!");
					}
					this[field] = fields[field];
				}
			}
			
			// get and execute the constructor to do the initialize process.
			if (param.Constructor) {
				if (typeof param.Constructor != "function") {
					throw new TypeError("Illegal function [" + method + "]!");
				}
				param.Constructor.apply(this, arguments);
			}
		};
		
		// set parent class and field "Super" for class		
		var parentClass = param.Extends ? param.Extends : Object;
		if (typeof parentClass != "function") {
			throw new TypeError("The parent class is not a function.");
		}
		if (parentClass != Object) {
			function F() {}
			F.prototype = parentClass.prototype;
			var prototype = new F();
			prototype.constructor = clazz;
			clazz.prototype = prototype;
		}
		clazz.prototype.Super = parentClass;
		
		// read methods and add to class(use prototype)
		if (param.Methods) {
			var methods = param.Methods;
			for (var method in methods) {
				if (typeof methods[method] != "function") {
					throw new TypeError("Illegal function [" + method + "]!");
				}
				clazz.prototype[method] = methods[method];
			}
		}
		
		// read static variables and methods and add to class
		if (param.Statics) {
			var statics = param.Statics;
			for (var name in statics) {
				clazz[name] = statics[name];
			}
		}
		
		// create the specified namespace and append the class to it.
		var name = param.Namespace;
		if (!name) {
			throw new Error("Please specify the Namespace.");
		}
		if (name.length == 0 || name.indexOf(" ") != -1 || name.charAt(0) == '.' 
			|| name.charAt(name.length - 1) == '.' || name.indexOf("..") != -1) {
			throw new Error("illegal Namespace: " + name);
		}
		var parts = name.split('.');
		var container = window;
	    for(var i = 0; i < parts.length - 1; i++) {
	        var part = parts[i];
	        // If there is no property of container with this name, create an empty object.
	        if (!container[part]) {
				container[part] = {};
			} else if (typeof container[part] != "object") {
	            // If there is already a property, make sure it is an object
	            var n = parts.slice(0, i).join('.');
	            throw new Error(n + " already exists and is not an object");
	        }
	        container = container[part];
	    }
		container[parts[parts.length - 1]] = clazz;
		
		return clazz;
	};
})(window);